package com.bestv.search.management.command;

import com.bestv.search.common.dataSource.DataSourceKey;
import com.bestv.search.common.dataSource.DataSourceKeyUtil;
import com.bestv.search.common.model.AccessLog;
import com.bestv.search.common.model.SysUser;
import com.bestv.search.common.service.AccessLogManager;
import com.bestv.search.common.util.Excel;
import com.bestv.search.common.util.ExcelSheet;
import com.bestv.search.common.util.StringConst;
import com.bestv.search.management.servlet.BuildChartServlet;
import org.apache.log4j.Logger;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.labels.CategoryToolTipGenerator;
import org.jfree.chart.labels.PieToolTipGenerator;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.data.general.Dataset;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.data.general.PieDataset;
import org.jfree.util.Log;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author Justin Luo
 */
public class AccessLogCommand {

    private static final String DO_HIT = "doHit";
    private static final String DO_HIT_TOP_SUGGEST_SEARCH = "doHitTopSuggestSearch";
    private static final String DOTOP = " 人气搜索次数 ";
    private static final String DOSUGGEST = " 即时提示次数  ";
    private static final String DOHIT = " 有效搜索次数  ";
    private static final String DOSEARCH = " 搜索次数 ";
    private static final String DOOTHER = " 其他  ";
    private static final String PIE_CHART = "pie";
    private static final int MINUTE_INTERVAL = 15;

    private Logger logger = Logger.getLogger(AccessLogCommand.class);
    private AccessLogManager accessLogManager;

    public void saveAccessLogList(List<AccessLog> list, String siteCode) {

        logger.info("Save access log into DB started :" + list.size());

        DataSourceKey key = DataSourceKeyUtil.convert(siteCode);
        accessLogManager.saveOrUpdateAccessLog(key, list);

        logger.info("Save access log into DB finished.");
    }

    public Map<String, Dataset> getChartDatasetAndToolTipId(SysUser user, Map<String, String[]> map, DataSourceKey dsKey) {
        String toolTipId = "";
        String[] chartName = map.get("chartName");
        String[] chartType = map.get("chartType");
        String[] subType = map.get("subType");
        String[] startDate = map.get("startDate");
        String[] endDate = map.get("endDate");
        String[] serverNo = map.get("serverNo");

        // Gets logs from DB
        List<AccessLog> logs = null;
        SimpleDateFormat xAxisLabelFormat = null;

        // Chart type is 'pie', endDate used to get data from DB
        if (chartType[0].equals(PIE_CHART)) {
            startDate = endDate;
        }

        if (StringConst.MINUTE.equals(subType[0])) {
            int serverNoInt = 0;
            if (serverNo != null && !serverNo[0].equals(StringConst.EMPTY)) {
                try {
                    serverNoInt = Integer.valueOf(serverNo[0]);
                } catch (Exception e) {
                    Log.error("Invalid serverNo " + serverNo[0]);
                    serverNoInt = 0;
                }
            }
            xAxisLabelFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
            Date endDateTime = convertDateTime(endDate[0]);
            if (chartType[0].equals(PIE_CHART)) {
                Calendar c = Calendar.getInstance();
                c.setTime(endDateTime);
                c.add(Calendar.MINUTE, MINUTE_INTERVAL);
                endDateTime = c.getTime();
            }
            logs = accessLogManager.getAccessLog(dsKey, convertDateTime(startDate[0]), endDateTime,
                    getTypes(chartName[0]), serverNoInt);
            toolTipId = StringConst.MINUTETOOLTIPMAP;
        } else if (subType != null && "daily".equals(subType[0])) {
            xAxisLabelFormat = new SimpleDateFormat("yyyy-MM-dd");
            logs = accessLogManager
                    .getByDate(dsKey, convert(startDate[0]), convert(endDate[0]), getTypes(chartName[0]));
            toolTipId = "dailyToolTipMap";
        } else if (subType != null && "month".equals(subType[0])) {
            logs = accessLogManager.getAccessLogByMonth(dsKey, convert(startDate[0]), convert(endDate[0]),
                    getTypes(chartName[0]));
            xAxisLabelFormat = new SimpleDateFormat("yyyy-MM");
            toolTipId = "monthToolTipMap";
        } else {
            logger.error("Parameters is not correctly:  " + subType);
            return null;
        }

        Map<String, Dataset> result = new HashMap<String, Dataset>();
        result.put(toolTipId, getDataset(logs, chartName[0], chartType[0], subType[0], xAxisLabelFormat));
        return result;
    }

    // Gets Dataset by access log list.
    private Dataset getDataset(List<AccessLog> logs, String chartName, String chartType, String subType,
                               SimpleDateFormat xAxisLabelFormat) {
        Dataset dataset = chartType.equals(PIE_CHART) ? new DefaultPieDataset() : new DefaultCategoryDataset();

        // Fills access logs to Dataset.
        int value = 0;
        for (int i = 0; i < logs.size(); i++) {

            AccessLog currLog = logs.get(i);
            String rowKey = getTypeNameByID(currLog.getType());
            String columnKey = xAxisLabelFormat.format(currLog.getAccessLowerTime());

            if (i == 0) {
                value = logs.get(i).getCount();
                // Add this first one value;
                if (dataset instanceof DefaultCategoryDataset) {
                    ((DefaultCategoryDataset) dataset).setValue(value, rowKey, columnKey);
                } else {
                    ((DefaultPieDataset) dataset).setValue(rowKey, value);
                }
            } else {
                String lastRowKey = getTypeNameByID(logs.get(i - 1).getType());
                String lastColumnKey = xAxisLabelFormat.format(logs.get(i - 1).getAccessLowerTime());

                // Current and last logs are same type and date, sum values.
                if (lastRowKey.equals(rowKey) && lastColumnKey.equals(columnKey)) {
                    value += currLog.getCount();
                } else {
                    value = currLog.getCount();
                }

                // Adds or updates value into dataset
                if (dataset instanceof DefaultCategoryDataset) {
                    ((DefaultCategoryDataset) dataset).setValue(value, rowKey, columnKey);
                } else {
                    ((DefaultPieDataset) dataset).setValue(rowKey, value);
                }
            }
        }
        return dataset;
    }

    public HSSFWorkbook createExcel(SysUser user, Map<String, String[]> map, DataSourceKey dsKey) {
        List<AccessLog> logs = null;

        String[] subType = map.get("subType");
        String[] startDate = map.get("startDate");
        String[] endDate = map.get("endDate");
        String[] chartName = map.get("chartName");
        String[] serverNo = map.get("serverNo");

        if (StringConst.MINUTE.equals(subType[0])) {
            int serverNoInt = 0;
            if (serverNo != null && !serverNo[0].equals(StringConst.EMPTY)) {
                try {
                    serverNoInt = Integer.valueOf(serverNo[0]);
                } catch (Exception e) {
                    Log.error("Invalid serverNo " + serverNo[0]);
                    serverNoInt = 0;
                }
            }
            Date endDateTime = convertDateTime(endDate[0]);
            if (subType[0].equals(PIE_CHART)) {
                Calendar c = Calendar.getInstance();
                c.setTime(endDateTime);
                c.add(Calendar.MINUTE, MINUTE_INTERVAL);
                endDateTime = c.getTime();
            }
            logs = accessLogManager.getAccessLog(dsKey, convertDateTime(startDate[0]), convertDateTime(endDate[0]),
                    getTypes(chartName[0]), serverNoInt);
        } else if ("daily".equals(subType[0])) {
            logs = accessLogManager
                    .getByDate(dsKey, convert(startDate[0]), convert(endDate[0]), getTypes(chartName[0]));
        } else if ("month".equals(subType[0])) {
            logs = accessLogManager.getAccessLogByMonth(dsKey, convert(startDate[0]), convert(endDate[0]),
                    getTypes(chartName[0]));
        } else {
            Log.error("Parameters is not correctly:  " + subType);
            return null;
        }

        String sheetName = null;
        if (chartName[0].equals(DO_HIT_TOP_SUGGEST_SEARCH)) {
            sheetName = "搜索请求统计";
        } else {
            sheetName = "有效搜索请求统计";
        }

        Excel excel = new Excel();
        HSSFWorkbook book = excel.create(formatDataForExport(logs, sheetName, subType));

        return book;
    }

    public HSSFWorkbook createExcelForLastTwoWeeks(SysUser user, Map<String, String[]> map, DataSourceKey dsKey)
            throws IOException {
        String chartName = DO_HIT_TOP_SUGGEST_SEARCH;

        Calendar today = Calendar.getInstance();
        today.add(Calendar.DAY_OF_YEAR, -1);
        Date thisWeekLastDay = today.getTime();
        today.add(Calendar.DAY_OF_YEAR, -6);
        Date thisWeekFirstDay = today.getTime();
        List<AccessLog> thisWeekLogs = accessLogManager.getByDate(dsKey, thisWeekFirstDay, thisWeekLastDay,
                getTypes(chartName));

        today.add(Calendar.DAY_OF_YEAR, -1);
        Date lastWeekLastDay = today.getTime();
        today.add(Calendar.DAY_OF_YEAR, -6);
        Date lastWeekFirstDay = today.getTime();
        List<AccessLog> lastWeekLogs = accessLogManager.getByDate(dsKey, lastWeekFirstDay, lastWeekLastDay,
                getTypes(chartName));

        // Gets data for picture
        List<AccessLog> lastTwoWeekLogs = accessLogManager.getByDate(dsKey, lastWeekFirstDay, thisWeekLastDay,
                getTypes(chartName));
        Dataset dataset = getDataset(lastTwoWeekLogs, "搜索请求统计", "line", StringConst.DAILY, new SimpleDateFormat(
                "yyyy-MM-dd"));
        // Gets chart
        JFreeChart chart = BuildChartServlet.createChart(dataset, "所有请求统计 ", "", "", chartName, "line");
        BufferedImage buffer = chart.createBufferedImage(900, 450);
        ByteArrayOutputStream picture = new ByteArrayOutputStream();
        ImageIO.write(buffer, "png", picture);

        Excel excel = new Excel();
        HSSFWorkbook book = excel.create(formatLastTwoWeekDataForExport(thisWeekLogs, lastWeekLogs));
        HSSFSheet sheet = book.getSheetAt(0);
        excel.insertPicture(sheet, picture, 0, 26);

        return book;
    }

    private ExcelSheet formatDataForExport(List<AccessLog> logs, String sheetName, String[] subType) {
        int rowHeaderLength = 3;
        if ("daily".equals(subType[0])) {
            rowHeaderLength = 4;
        } else if (StringConst.MINUTE.equals(subType[0])) {
            rowHeaderLength = 5;
        }

        ExcelSheet sheet = new ExcelSheet();
        sheet.setSheetName(sheetName);

        List<String> headers = new ArrayList<String>();
        headers.add("名称");
        headers.add("描述");
        headers.add("年份");

        if (rowHeaderLength == 4) {
            headers.add("月份");
        } else if (rowHeaderLength == 5) {
            headers.add("月份");
            headers.add("日期");
        }

        List<String[]> data = new ArrayList<String[]>();
        int maxColumnIndex = 0;
        int minColumnIndex = 0;
        // Format log type
        for (int i = 0; i < logs.size(); i++) {
            String[] row = null;
            AccessLog log = logs.get(i);
            String typeName = getTypeNameByID(log.getType());

            Calendar c = Calendar.getInstance();
            c.setTime(log.getAccessLowerTime());
            int year = c.get(Calendar.YEAR);
            int month = c.get(Calendar.MONTH) + 1;
            int day = c.get(Calendar.DAY_OF_MONTH);
            int hour = c.get(Calendar.HOUR_OF_DAY);
            int minute = c.get(Calendar.MINUTE);

            for (String[] tempRow : data) {
                if (rowHeaderLength == 5) {
                    // has exist row in the data list.
                    if (typeName.equals(tempRow[0]) && year == Integer.valueOf(tempRow[2])
                            && month == Integer.valueOf(tempRow[3]) && day == Integer.valueOf(tempRow[4])) {
                        row = tempRow;
                        break;
                    }
                } else if (rowHeaderLength == 4) {
                    // has exist row in the data list.
                    if (typeName.equals(tempRow[0]) && year == Integer.valueOf(tempRow[2])
                            && month == Integer.valueOf(tempRow[3])) {
                        row = tempRow;
                        break;
                    }
                } else {
                    // has exist row in the data list.
                    if (typeName.equals(tempRow[0]) && year == Integer.valueOf(tempRow[2])) {
                        row = tempRow;
                        break;
                    }
                }
            }

            if (row == null) {
                row = new String[rowHeaderLength + 1440 / MINUTE_INTERVAL];
                row[0] = typeName;
                row[1] = getTypeDescriptionByID(log.getType());
                row[2] = String.valueOf(year);
                if (rowHeaderLength == 4) {
                    row[3] = String.valueOf(month);
                } else if (rowHeaderLength == 5) {
                    row[3] = String.valueOf(month);
                    row[4] = String.valueOf(day);
                }
                data.add(row);
            }

            // add values for daily export.
            int baseRowIndex = 0;
            if (rowHeaderLength == 5) {
                baseRowIndex = hour * 4 + minute / MINUTE_INTERVAL + 1;
            } else if (rowHeaderLength == 4) {
                baseRowIndex = day;
            } else {
                baseRowIndex = month;
            }
            row[baseRowIndex + rowHeaderLength - 1] = row[baseRowIndex + rowHeaderLength - 1] == null ? String
                    .valueOf(log.getCount()) : String.valueOf(Integer.valueOf(row[baseRowIndex + rowHeaderLength - 1])
                    + log.getCount());

            if (maxColumnIndex == 0 || baseRowIndex + rowHeaderLength - 1 > maxColumnIndex) {
                maxColumnIndex = baseRowIndex + rowHeaderLength - 1;
            }
            if (minColumnIndex == 0 || baseRowIndex + rowHeaderLength - 1 < minColumnIndex) {
                minColumnIndex = baseRowIndex + rowHeaderLength - 1;
            }
        }

        // add coulmn headers
        for (int i = minColumnIndex; i <= maxColumnIndex; i++) {
            String headerNameSuffix;
            if (rowHeaderLength == 5) {
                headers.add((i + 1 - rowHeaderLength) / 4 + "点" + ((i - rowHeaderLength) % 4) * MINUTE_INTERVAL + "分");
            } else {
                if (rowHeaderLength == 4) {
                    headerNameSuffix = "号";
                } else {
                    headerNameSuffix = "月";
                }
                headers.add(String.valueOf(i + 1 - rowHeaderLength) + headerNameSuffix);
            }
        }
        sheet.setDataHeader(headers);

        List<String[]> actualSheetData = new ArrayList<String[]>();
        for (String[] row : data) {
            String[] newRow = new String[maxColumnIndex - minColumnIndex + 1 + rowHeaderLength];
            if (rowHeaderLength == 3) {
                newRow[0] = row[0];
                newRow[1] = row[1];
                newRow[2] = row[2];
            }
            if (rowHeaderLength == 4) {
                newRow[0] = row[0];
                newRow[1] = row[1];
                newRow[2] = row[2];
                newRow[3] = row[3];
            }

            if (rowHeaderLength == 5) {
                newRow[0] = row[0];
                newRow[1] = row[1];
                newRow[2] = row[2];
                newRow[3] = row[3];
                newRow[4] = row[4];
            }
            for (int i = minColumnIndex; i <= maxColumnIndex; i++) {
                newRow[i - minColumnIndex + rowHeaderLength] = row[i];
            }
            actualSheetData.add(newRow);
        }
        sheet.setData(actualSheetData);

        return sheet;
    }

    private ExcelSheet formatLastTwoWeekDataForExport(List<AccessLog> thisWeekLogs, List<AccessLog> lastWeekLogs) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy/MM/dd");

        ExcelSheet sheet = new ExcelSheet();
        sheet.setSheetName("搜索请求统计");

        // 导出列名列表
        List<String> headers = new ArrayList<String>();
        // 导出数据
        List<String[]> data = new ArrayList<String[]>();

        // 获取上一周数据周数据
        String[][] lastWeekLogsFormated = null;
        if (lastWeekLogs.size() > 0) {
            String title = format.format(lastWeekLogs.get(0).getAccessLowerTime()) + "到"
                    + format.format(lastWeekLogs.get(lastWeekLogs.size() - 1).getAccessLowerTime());
            headers.add(title);

            lastWeekLogsFormated = FormatOneWeekData(lastWeekLogs, format);
            for (String[] row : lastWeekLogsFormated)
                data.add(row);
        }

        // 获取当前周数据
        String[][] thisWeekLogsFormated = null;
        if (thisWeekLogs.size() > 0) {
            String title = format.format(thisWeekLogs.get(0).getAccessLowerTime()) + "到"
                    + format.format(thisWeekLogs.get(thisWeekLogs.size() - 1).getAccessLowerTime());
            if (headers.size() == 0) {
                headers.add(title);
            } else {
                String[] titleRow = new String[]{title};
                data.add(titleRow);
            }

            thisWeekLogsFormated = FormatOneWeekData(thisWeekLogs, format);
            for (String[] row : thisWeekLogsFormated)
                data.add(row);
        }

        // 形成周对比数据
        if (lastWeekLogsFormated != null && thisWeekLogsFormated != null) {
            if (lastWeekLogsFormated[7][1] != null && lastWeekLogsFormated[8][1] != null
                    && thisWeekLogsFormated[7][1] != null && thisWeekLogsFormated[8][1] != null) {
                String[] weekComparedTitle = new String[]{"周对比"};
                data.add(weekComparedTitle);

                int lastWeekMaxSearchCount = Integer.valueOf(lastWeekLogsFormated[7][1]);
                int lastWeekAvgSearchCount = Integer.valueOf(lastWeekLogsFormated[8][1]);
                int thisWeekMaxSearchCount = Integer.valueOf(thisWeekLogsFormated[7][1]);
                int thisWeekAvgSearchCount = Integer.valueOf(thisWeekLogsFormated[8][1]);

                String sign = "";
                if (thisWeekMaxSearchCount - lastWeekMaxSearchCount >= 0) {
                    sign = "+";
                }

                String[] weekComparedMaxSearchCount = new String[]{
                        "最大搜索次数浮动",
                        sign + String.valueOf(thisWeekMaxSearchCount - lastWeekMaxSearchCount),
                        sign
                                + String.format("%.2f", Float.valueOf(thisWeekMaxSearchCount - lastWeekMaxSearchCount)
                                / Float.valueOf(lastWeekMaxSearchCount) * 100) + "%"};
                data.add(weekComparedMaxSearchCount);

                sign = "";
                if (thisWeekAvgSearchCount - lastWeekAvgSearchCount >= 0) {
                    sign = "+";
                }
                String[] weekComparedAvgSearchCount = new String[]{
                        "平均搜索次数浮动",
                        sign + String.valueOf(thisWeekAvgSearchCount - lastWeekAvgSearchCount),
                        sign
                                + String.format("%.2f", Float.valueOf(thisWeekAvgSearchCount - lastWeekAvgSearchCount)
                                / Float.valueOf(lastWeekAvgSearchCount) * 100) + "%"};
                data.add(weekComparedAvgSearchCount);
            }
        }

        // 添加表头
        sheet.setDataHeader(headers);

        // 添加数据
        sheet.setData(data);

        return sheet;
    }

    private String[][] FormatOneWeekData(List<AccessLog> oneWeekLogs, SimpleDateFormat format) {
        String[][] result = new String[10][9];

        result[0][0] = "名称";
        result[0][1] = "描述";
        result[1][0] = "doSearch";
        result[1][1] = getTypeDescriptionByID(0);
        result[2][0] = "doTop";
        result[2][1] = getTypeDescriptionByID(10);
        result[3][0] = "doSuggest";
        result[3][1] = getTypeDescriptionByID(20);
        result[4][0] = "doHit";
        result[4][1] = getTypeDescriptionByID(30);

        int i = 1;
        int maxSearchCount = 0, sumSearchCount = 0, logsCount = 0, searchCount = 0;
        String maxSearchDate = null;
        String currDate = null;
        for (AccessLog log : oneWeekLogs) {
            if (currDate == null || !format.format(log.getAccessLowerTime()).equals(currDate)) {
                i++;
                if (result[0][i] == null) {
                    result[0][i] = format.format(log.getAccessLowerTime());
                }
            }
            switch (log.getType()) {
                case 10:
                    result[2][i] = String.valueOf(result[2][i] == null ? log.getCount() : log.getCount()
                            + Integer.valueOf(result[2][i]));
                    break;
                case 20:
                    result[3][i] = String.valueOf(result[3][i] == null ? log.getCount() : log.getCount()
                            + Integer.valueOf(result[3][i]));
                    break;
                case 30:
                    result[4][i] = String.valueOf(result[4][i] == null ? log.getCount() : log.getCount()
                            + Integer.valueOf(result[4][i]));
                    break;
                default:
                    if (currDate == null) {
                        searchCount = log.getCount();
                        maxSearchCount = searchCount;
                        maxSearchDate = format.format(log.getAccessLowerTime());
                        logsCount = 1;
                    } else {
                        if (!format.format(log.getAccessLowerTime()).equals(currDate)) {
                            result[1][i - 1] = String.valueOf(searchCount);
                            if (searchCount > maxSearchCount) {
                                maxSearchCount = searchCount;
                                maxSearchDate = currDate;
                            }
                            searchCount = log.getCount();
                            logsCount++;
                        } else {
                            searchCount += log.getCount();
                        }
                    }
                    sumSearchCount += log.getCount();
                    break;
            }

            if (currDate == null || !format.format(log.getAccessLowerTime()).equals(currDate)) {
                currDate = format.format(log.getAccessLowerTime());
            }
        }

        // Compare with last one day's searchCount.
        if (searchCount > maxSearchCount) {
            maxSearchCount = searchCount;
            maxSearchDate = currDate;
        }
        result[1][i] = String.valueOf(searchCount);

        if (maxSearchDate != null) {
            int avgSearchCount = sumSearchCount / logsCount;

            // One blank line
            result[5][0] = "";

            result[6][0] = "最大搜索日期为 ";
            result[6][1] = maxSearchDate;
            result[7][0] = "最大搜索次数为";
            result[7][1] = String.valueOf(maxSearchCount);
            result[8][0] = "平均搜索次数为";
            result[8][1] = String.valueOf(avgSearchCount);

            // One blank line
            result[9][0] = "";
        }
        return result;
    }

    public AccessLogManager getAccessLogManager() {
        return accessLogManager;
    }

    public void setAccessLogManager(AccessLogManager accessLogManager) {
        this.accessLogManager = accessLogManager;
    }

    // Converts date string to date object
    private Date convert(String date) {
        Calendar c = null;
        String format = "(\\d{4})-(\\d{2})-?(\\d{0,2})";
        Pattern pattern = Pattern.compile(format);
        Matcher matcher = pattern.matcher(date);
        if (matcher.matches()) {
            c = Calendar.getInstance();
            int year = Integer.parseInt(matcher.group(1));
            int month = Integer.parseInt(matcher.group(2)) - 1;

            // If convert month(etc.2012-10) to date object, set values of day
            // to "01"
            int day = Integer.parseInt(matcher.group(3).equals("") ? "01" : matcher.group(3));
            c.set(year, month, day, 0, 0, 0);
            c.set(Calendar.MILLISECOND, 0);
        } else {
            logger.error("Date format is not correctly.");
        }
        return c.getTime();
    }

    // Converts date string to date object
    private Date convertDateTime(String dateTime) {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        try {
            return df.parse(dateTime);
        } catch (ParseException e) {
            logger.error("Date and time format is not correctly, dateTime:" + dateTime);
            e.printStackTrace();
            return null;
        }
    }

    // Gets actual request type by chart name
    private int[] getTypes(String chartName) {
        if (chartName.equals(DO_HIT)) {
            int[] types = {30};
            return types;
        } else if (chartName.equals(DO_HIT_TOP_SUGGEST_SEARCH)) {
            int[] types = {0, 1, 2, 10, 20, 30};
            return types;
        }
        return null;
    }

    private String getTypeNameByID(int typeId) {
        switch (typeId) {
            case 10:
                return "doTop";
            case 20:
                return "doSuggest";
            case 30:
                return "doHit";
            default:
                return "doSearch";
        }
    }

    private String getTypeDescriptionByID(int typeId) {
        switch (typeId) {
            case 10:
                return DOTOP;
            case 20:
                return DOSUGGEST;
            case 30:
                return DOHIT;
            default:
                return DOSEARCH;
        }
    }

    public static final class AccessLogCategoryTooltipGenerator implements CategoryToolTipGenerator {
        @SuppressWarnings("rawtypes")
        public String generateToolTip(CategoryDataset dataSet, int series, int category) {
            StringBuilder result = new StringBuilder();

            List rows = dataSet.getRowKeys();
            String typeName = rows.get(series).toString();
            if (typeName.equals("doTop")) {
                result.append(DOTOP);
            } else if (typeName.equals("doSuggest")) {
                result.append(DOSUGGEST);
            } else if (typeName.equals("doHit")) {
                result.append(DOHIT);
            } else if (typeName.equals("doSearch")) {
                result.append(DOSEARCH);
            } else {
                result.append(DOOTHER);
            }

            List columns = dataSet.getColumnKeys();
            result.append("(");
            result.append(columns.get(category).toString());
            result.append(",  ");
            result.append(dataSet.getValue(typeName, columns.get(category).toString()).intValue());
            result.append(")");

            return result.toString();
        }
    }

    public static final class AccessLogPieToolTipGenerator implements PieToolTipGenerator {
        public String generateToolTip(PieDataset dataSet, @SuppressWarnings("rawtypes") Comparable key) {
            StringBuilder result = new StringBuilder();

            if (key.equals("doTop")) {
                result.append(DOTOP);
            } else if (key.equals("doSuggest")) {
                result.append(DOSUGGEST);
            } else if (key.equals("doHit")) {
                result.append(DOHIT);
            } else if (key.equals("doSearch")) {
                result.append(DOSEARCH);
            } else {
                result.append(DOOTHER);
            }
            result.append(" ( ");
            result.append(dataSet.getValue(key).intValue());
            result.append(", ");

            int summary = 0;
            for (int i = 0; i < dataSet.getItemCount(); i++) {
                summary += dataSet.getValue(i).intValue();
            }

            double percentage = dataSet.getValue(key).doubleValue() / summary;
            NumberFormat nf = NumberFormat.getPercentInstance();
            result.append(nf.format(percentage));
            result.append(")");

            return result.toString();
        }
    }
}